/*
 * @(#)AutoTaskStartSubWorkflow.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.workflow.action;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionException;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.EventLogger;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemFunctionConstant;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.Utility;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.dao.UserRecordDAObject;
import com.dcivision.workflow.WorkflowErrorConstant;
import com.dcivision.workflow.bean.MtmWfProgressWfProgress;
import com.dcivision.workflow.bean.MtmWorkflowChildParentProgress;
import com.dcivision.workflow.bean.MtmWorkflowProgressSystemObject;
import com.dcivision.workflow.bean.MtmWorkflowProgressUserRecord;
import com.dcivision.workflow.bean.MtmWorkflowTrackInterruptReq;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.bean.WorkflowProgressAttachment;
import com.dcivision.workflow.bean.WorkflowRecord;
import com.dcivision.workflow.core.WorkflowProgressManager;
import com.dcivision.workflow.dao.MtmWfProgressWfProgressDAObject;
import com.dcivision.workflow.dao.MtmWorkflowChildParentProgressDAObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressSystemObjectDAObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressUserRecordDAObject;
import com.dcivision.workflow.dao.WorkflowProgressAttachmentDAObject;
import com.dcivision.workflow.dao.WorkflowProgressDAObject;
import com.dcivision.workflow.dao.WorkflowRecordDAObject;
import com.dcivision.workflow.web.MaintWorkflowRecordForm;

/**
 * This is a class that acts as a template for coding automatic task to trigger sub workflow
 *
 * @author Dick Xie
 * @company DCIVision Limited
 * @creation date 01/11/2006
 * @version $Revision: 1.4.2.2 $
 */
 public class AutoTaskStartSubWorkflow  implements  Job {

  public static final String REVISION = "$Revision: 1.4.2.2 $";

  protected Log log = LogFactory.getLog(this.getClass().getName());
  protected Integer subworkflowRecordID = null; //* the subworkflow record id;
  protected boolean parentDependent;
  protected String currentProgressStatus = null;
  protected boolean  bAutoExecuteNextStep = true;
  protected boolean  bCreateNextWorkflowProgress = true;
  Connection conn = null;

  private boolean   isAllowUploadParentAttachments = true;

  public boolean isParentDependent() {
    return parentDependent;
  }

  public void setParentDependent(boolean parentDependent) {
    this.parentDependent = parentDependent;
  }

  public String getCurrentProgressStatus() {
    return currentProgressStatus;
  }

  public Integer getSubworkflowRecordID() {
    return subworkflowRecordID;
  }

  public SessionContainer getSessionContainer() {
    SessionContainer sessionCon = new SessionContainer();
    return sessionCon;
    }

  public AutoTaskStartSubWorkflow() {


    this.parentDependent = true;

    //* depends on whether want the subworkflow to be running independent of the parent workflow or not
    if (this.parentDependent) {
      this.currentProgressStatus = WorkflowProgress.STATUS_PENDING; //* subworkflow has close relationship with parent
    } else {
      this.currentProgressStatus = WorkflowProgress.STATUS_GENERAL_ACCOMPLISHMENT; //* subflow running independent of the parnet workflow
    }
  }

  public synchronized void execute(org.quartz.JobExecutionContext context) throws JobExecutionException {
    log.info("***** AutoTaskStartSubWorkflowTemplate workflow processor BEGIN *****");
    WorkflowProgress currentProgress = (WorkflowProgress)context.getJobDetail().getJobDataMap().get("currentProgress");
    MtmWorkflowTrackInterruptReq trackInterruptReq = (MtmWorkflowTrackInterruptReq)context.getJobDetail().getJobDataMap().get("trackInterruptReq");

    Integer trigerEventUserID = new Integer(0);
    String serverName = "127.0.0.1";
    String functionName = SystemFunctionConstant.WORKFLOW_TASK;
    String errorMessage = "";

    try {
      //* get the DB Connection
      this.conn = DataSourceFactory.getConnection();
      SessionContainer sessionCon = this.getSessionContainer();

      //* create required DAObject
      WorkflowRecordDAObject recordDAO = new WorkflowRecordDAObject(sessionCon, conn);
      WorkflowProgressManager progressManager = new WorkflowProgressManager(sessionCon, conn);
      MtmWorkflowChildParentProgressDAObject subworkflowDAO = new MtmWorkflowChildParentProgressDAObject(sessionCon, conn);
      WorkflowRecord workflowRecord = (WorkflowRecord)recordDAO.getObjectByID(currentProgress.getWorkflowRecordID());
      MtmWorkflowProgressSystemObjectDAObject progressObjectDAO = new MtmWorkflowProgressSystemObjectDAObject(sessionCon, conn);
      MtmWfProgressWfProgressDAObject mtmWfProgressWfProgressDAO = new MtmWfProgressWfProgressDAObject(sessionCon, conn);
      this.subworkflowRecordID = workflowRecord.getInterruptWorkflowRecordID();
      //* get relevant information from
      //AbstractBaseObject workflowObject = (AbstractBaseObject) dataMap.get("WORKFLOW_OBJECT");
      //log.debug("workflow object class name: "+workflowObject.getClass().getName());
      //Integer docID = workflowObject.getID();

      log.info("current progress' workflow step id: "+currentProgress.getWorkflowStepID());
      Integer userRecordID = currentProgress.getUpdaterID();
      UserRecordDAObject userDAO = new UserRecordDAObject(sessionCon, conn);
      log.info("userRecordID: "+userRecordID);
      UserRecord userRecord = (UserRecord) userDAO.getObjectByID(userRecordID);
      sessionCon.setUserRecord(userRecord);

      /*************************************************************
       *  get Event Log Information Begin
       *************************************************************/
      if (!Utility.isEmpty(sessionCon.getUserRecordID())) {
        trigerEventUserID = sessionCon.getUserRecordID();
      }

      if (!Utility.isEmpty(sessionCon.getUserIPAddress())) {
        serverName = sessionCon.getUserIPAddress();
      }
      errorMessage =  "AutoTaskStartSubWorkflow.java -- Track ID: " + currentProgress.getTrackID() +
                      ", Workflow Progress ID : " + currentProgress.getID() +
                      ", Workflow Step ID: " + currentProgress.getWorkflowStepID() +
                      "<br> ";
      /*************************************************************
       *  get Event Log Information End
       *************************************************************/

      //* do what you want below
      WorkflowRecord SubWorkflowRecord = (WorkflowRecord) recordDAO.getObjectByID(this.subworkflowRecordID );
      MaintWorkflowRecordForm recordForm = new MaintWorkflowRecordForm();
      recordForm.setFormData(SubWorkflowRecord);
      log.debug("start workflow start new track");
      WorkflowProgress workflowProgress = (WorkflowProgress) progressManager.startWorkflowTrack(recordForm);
      log.debug("end workflow start new track");

      if (isAllowUploadParentAttachments) {
        setSubWorkFlowAttachmentsFromParentProgress(workflowProgress, currentProgress, conn);
      }

      recordForm.setWorkflowObject(trackInterruptReq);
      // insert MtmWorkflowProgressSystemObject table
      List ProgressAndProgressList = mtmWfProgressWfProgressDAO.getListByParentProgressID(workflowProgress.getID());
      JobDataMap dataMap = new JobDataMap();
      dataMap.put("WORKFLOW_OBJECT", recordForm.getWorkflowObject());
      dataMap.put("WORKFLOW_PROGRESS", currentProgress);


      MtmWorkflowProgressSystemObject systemObject = new MtmWorkflowProgressSystemObject();

      systemObject.setTrackID(workflowProgress.getTrackID());
      if (!Utility.isEmpty(ProgressAndProgressList)) {
        MtmWfProgressWfProgress progressAndProgress = (MtmWfProgressWfProgress)ProgressAndProgressList.get(0);
        systemObject.setWorkflowProgressID(progressAndProgress.getChildProgressID());
      }
      systemObject.setBeanClassName(recordForm.getWorkflowObject().getClass().getName());
      systemObject.setObjectID(recordForm.getWorkflowObject().getID());
      systemObject.setParameterObject(dataMap.getWrappedMap());
      progressObjectDAO.insertObject(systemObject);

      if (this.parentDependent) {
        log.debug("add workflow child parent progress record");
        MtmWorkflowChildParentProgress childWorkflowParentProgress = new MtmWorkflowChildParentProgress();
        childWorkflowParentProgress.setParentWorkflowProgressID(currentProgress.getID());
        childWorkflowParentProgress.setSubworkflowTrackID(workflowProgress.getTrackID());
        childWorkflowParentProgress = (MtmWorkflowChildParentProgress) subworkflowDAO.insertObject(childWorkflowParentProgress);
        log.debug("finish add workflow child parent progress record");
      }

      //* after the execution, set the desired appropriate out number
      //this.returnRoutineIndex = 1; //* should be between 0 and numOfRoutine-1
      //* if need to auto-Execute the following step, set the below variable to true (default false)
      this.bAutoExecuteNextStep=false; this.bCreateNextWorkflowProgress=true;

      this.conn.commit();
    } catch (ApplicationException appEx) {
      /***********************************
       *  Record the Eve
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, appEx.getMsgCode(), WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, appEx.toString() );

    }catch (Exception x){
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, ErrorConstant.COMMON_FATAL_ERROR, WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, x.toString() );

      log.error(x, x);
    }
    finally {
      try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
    }

    log.info("***** AutoTaskStartSubWorkflowTemplate workflow processor END   *****");
  }

  /**
   * if isAllowUploadParentAttachments is true then  bring attachments to subworkflow
   * @param workflowProgress
   * @param parentProgress
   * @param conn
   * @throws Exception
   */
  private void setSubWorkFlowAttachmentsFromParentProgress(WorkflowProgress workflowProgress, WorkflowProgress parentProgress, Connection conn) throws Exception {
    InputStream inputStream = null;
    FileOutputStream fos = null;
    int bufferSize = 8192;
    byte[] buffer = new byte[bufferSize];
    int length = -1;
    Integer trackID = parentProgress.getTrackID();
    SessionContainer sessionContainer = this.getSessionContainer();
    Integer userRecordID = parentProgress.getUpdaterID();
    UserRecordDAObject userDAO = new UserRecordDAObject(sessionContainer, conn);
    UserRecord userRecord = (UserRecord) userDAO.getObjectByID(userRecordID);
    sessionContainer.setUserRecord(userRecord);
    WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionContainer, conn);
    WorkflowProgressAttachmentDAObject attachmentDAO = new WorkflowProgressAttachmentDAObject(sessionContainer, conn);
    MtmWorkflowProgressUserRecordDAObject progressUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(sessionContainer, conn);
    List progressList = progressDAO.getListByTrackID(trackID);
    List allAttachmentList = new ArrayList();

    List progressUserList = progressUserRecordDAO.getCompletedUserProcessRecordByWorkflowProgressID(workflowProgress.getID());

    Integer progressUserID = null;
    if (!Utility.isEmpty(progressUserList)) {
      MtmWorkflowProgressUserRecord progressUser = (MtmWorkflowProgressUserRecord) progressUserList.get(0);
      progressUserID = new Integer(progressUser.getID().intValue());
    }

    // get all attachments from parent Track
    for (int i = 0; i < progressList.size(); i++) {
      WorkflowProgress progress = (WorkflowProgress) progressList.get(i);
      List subAttachmentList = attachmentDAO.getListByWorkflowProgressID(progress.getID());
      if (!Utility.isEmpty(subAttachmentList)) {
        allAttachmentList.addAll(subAttachmentList);
      }
    }

    for (Iterator iter = allAttachmentList.iterator(); iter.hasNext();) {
      WorkflowProgressAttachment tmpattachment = (WorkflowProgressAttachment) iter.next();
      if (WorkflowProgressAttachment.ATTACHED_SINGLE_FILE.equals(tmpattachment.getAttachmentType())) {
        String filePath = SystemParameterFactory.getSystemParameter(SystemParameterConstant.WORKFLOW_ATTACHMENT_PHYSICAL_PATH);
        String allFileName = filePath + "/" + tmpattachment.getExternalID();
        String convertedName = String.valueOf(System.currentTimeMillis());
        File convertedFile = new File(filePath + "/" + convertedName);
        while (convertedFile.exists()) {
          convertedName = convertedName + String.valueOf(System.currentTimeMillis());
          convertedFile = new File(filePath + "/" + convertedName);
        }
        File newfile = new File(allFileName);
        inputStream = new FileInputStream(newfile);

        WorkflowProgressAttachment attachment = new WorkflowProgressAttachment();
        attachment.setAttachmentName(tmpattachment.getAttachmentName());
        attachment.setExternalID(convertedName);
        attachment.setFlowType(WorkflowProgressAttachment.ATTACHED_SINGLE_FILE);
        attachment.setDataStream(inputStream);
        attachment.setContentSize(new Integer("" + newfile.length()));
        attachment.setAttachmentType(WorkflowProgressAttachment.ATTACHED_SINGLE_FILE);
        attachment.setMtmWorkflowProgressUserRecordID(progressUserID);
        attachmentDAO.insertObject(attachment);

        fos = new FileOutputStream(convertedFile);
        while ((length = inputStream.read(buffer, 0, bufferSize)) != -1) {
          fos.write(buffer, 0, length);
        }
        fos.flush();
        inputStream.close();
        fos.close();
      } else if (WorkflowProgressAttachment.ATTACHED_DMS_VERSION_SYSTEM_ID.equals(tmpattachment.getAttachmentType())) {
        tmpattachment.setMtmWorkflowProgressUserRecordID(progressUserID);
        attachmentDAO.insertObject(tmpattachment);
      }
    }

  }

  public boolean isAllowUploadParentAttachments() {
    return isAllowUploadParentAttachments;
  }

  public void setAllowUploadParentAttachments(boolean isAllowUploadParentAttachments) {
    this.isAllowUploadParentAttachments = isAllowUploadParentAttachments;
  }

}
